package com.mdms.hibernate;

import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.mdms.logger.SimplyMDLogger;
import com.mdms.utils.ConfigFolderUtils;
import org.hibernate.cfg.Environment;
import org.hibernate.mapping.PersistentClass;


public  final class HibernateUtils {
	
		private static SimplyMDLogger logger = new SimplyMDLogger(HibernateUtils.class);

		public final static String MINVEVRA_KEY = "MINEVRA";
		
		public final static String MDMS_KEY = "MDMS";
		
		private static Map configurations = new HashMap();

		private static Map sessionFactories = new HashMap();

		private static boolean initialized = false;

		public static synchronized  void init() {
			String methodName = "init";
			logger.debug(methodName, "START");
			//jesli zainicjowane juz to nie robimy ponownie szopki
			if (initialized){
				return;
			}
			// Create the initial SessionFactory from the default configuration
			// files
			try {

				// Read hibernate.properties, if present
				// configuration = new Configuration();
				// Use annotations: configuration = new AnnotationConfiguration();
				configurations.put(MINVEVRA_KEY, new Configuration());
				configurations.put(MDMS_KEY, new Configuration());


				//pobranie parametrow hibernate

				for (Iterator iter = configurations.keySet().iterator(); iter.hasNext();) {
					String key = (String) iter.next();
					Configuration configuration = (Configuration) configurations.get(key);
					File conf = new File(ConfigFolderUtils.getWWWConfigLocation()+File.separator+key+".hibernate.cfg.xml");
					configuration.configure(conf.getAbsoluteFile());
					Iterator iterMappings = configuration.getClassMappings();
					while (iterMappings.hasNext()) {
						PersistentClass persistentClass = (PersistentClass) iterMappings.next();

						//log.debug(methodName,"Persistent class name: " + persistentClass.getClassName());
						try {
							configuration.addClass(persistentClass.getMappedClass());
						} catch (Exception ex) {
							String c = ex.toString();
						}
					}
					configuration.buildMappings();
				}
				//jesli po inicjalizacji to oznaczmy ten stan
				initialized = true; 

			} catch (Throwable ex) {
				// We have to catch Throwable, otherwise we will miss
				// NoClassDefFoundError and other subclasses of Error
				throw new ExceptionInInitializerError(ex.getMessage());
			}
		}

		/**
		 * Private constructor
		 */
		private HibernateUtils() {

		}

		/**
		 * Returns the Hibernate configuration that was used to build the
		 * SessionFactory.
		 * 
		 * @return Configuration
		 */
		public static Configuration getConfiguration(String key) {
			return (Configuration) configurations.get(key);
		}

		/**
		 * Returns the cpm SessionFactory either from a static variable or a JNDI
		 * lookup.
		 * 
		 * @return SessionFactory
		 */
		public static synchronized SessionFactory getSessionFactory(String key) {
			String methodName = "getSessionFactory";
			Configuration configuration = (Configuration) configurations.get(key);
			
			String sfName = configuration.getProperty(Environment.SESSION_FACTORY_NAME);
			if (sfName != null && sessionFactories.get(key) != null) {
				try {
					return (SessionFactory) new InitialContext().lookup(sfName);
				} catch (NamingException ex) {
					throw new RuntimeException(ex);
				}
			} else if (sessionFactories.get(key) == null) {
				rebuildSessionFactory(key);
			}
			return (SessionFactory) sessionFactories.get(key);
		}

		/**
		 * Closes the current SessionFactory and releases all resources.
		 * <p>
		 * The only other method that can be called on HibernateUtil after this one
		 * is rebuildSessionFactory(Configuration).
		 */
		public static void shutdown() {
			// Close caches and connection pools
			for (Iterator iter = configurations.keySet().iterator(); iter.hasNext();) {
				String key = (String) iter.next();
				SessionFactory sessionFactory = ((SessionFactory) sessionFactories.get(key));
				if (sessionFactory != null) {
					sessionFactory.close();
				}
			}

			// Clear static variables
			sessionFactories = null;
			configurations = null;
		}

		/**
		 * Rebuild the Hades SessionFactory with the static Configuration.
		 * <p>
		 * Note that this method should only be used with static SessionFactory
		 * management, not with JNDI or any other external registry. This method
		 * also closes the old static variable SessionFactory before, if it is still
		 * open.
		 */
		public static synchronized SessionFactory rebuildSessionFactory(String key) {
			SessionFactory sessionFactory = 
					rebuildSessionFactory((Configuration) configurations.get(key), (SessionFactory) sessionFactories
							.get(key));
			sessionFactories.put(key, sessionFactory);
			return (SessionFactory) sessionFactories.get(key);
		}

		/**
		 * Rebuild the SessionFactory with the given Hibernate Configuration.
		 * <p>
		 * HibernateUtil does not configure() the given Configuration object, it
		 * directly calls buildSessionFactory(). This method also closes the old
		 * static variable SessionFactory before, if it is still open.
		 * 
		 * @param cfg
		 */
		public static synchronized SessionFactory rebuildSessionFactory(Configuration cfg, SessionFactory sessionFactory) {
			String methodName = "rebuildSessionFactory";
			if (sessionFactory != null && !sessionFactory.isClosed()) {
				sessionFactory.close();
			}
			if (cfg.getProperty(Environment.SESSION_FACTORY_NAME) != null) {
				return cfg.buildSessionFactory();
			} else {			
				sessionFactory = cfg.buildSessionFactory();
				return sessionFactory;
			}
		}

	}
